﻿package com.snzflash.components.grid 
{
	import com.snzflash.components.core.UIComponent;
	import com.snzflash.components.core.UIContainer;
	import com.snzflash.components.list.*;
	import com.snzflash.events.ComponentEvent;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Rectangle;
	import flash.utils.setTimeout;
	
	/**
	 * Базовый класс для сетки
	 * @author firsoff maxim, tel: +79222345364, skype: maxim.firsoff
	 */
	public class Grid extends UIComponent
	{
		protected var _dataProvider:Array;
		protected var _items:/*ListItemRenderer*/Array;
		protected var _itemsChanged:Boolean;
		protected var _numRows:int = 0;
		protected var _numColumns:int = 0;
		protected var _verticalGap:Number = 0;
		protected var _horizontalGap:Number = 0;
		protected var _itemWidth:Number = 0;
		protected var _itemHeight:Number = 0;
		protected var _itemRenderer:Class = ListItemRenderer;
		protected var _selectedItem:Object;
		protected var _selectedRenderer:ListItemRenderer;
		protected var _content:UIContainer;
		
		// параметры скроллирования
		protected var _maxHorizontalScrollPosition:Number = 0;
		protected var _maxVerticalScrollPosition:Number = 0;
		protected var _horizontalScrollPosition:Number = 0;
		protected var _verticalScrollPosition:Number = 0;
		protected var _verticalScrollProgress:Number = 0;
		protected var _horizontalScrollProgress:Number = 0;
		protected var _propertiesChanged:Boolean;
		
		public function Grid() 
		{
			super();	
		};
		
		
		override protected function initProperties():void 
		{
			super.initProperties();
			_items = new Array();
		};
		
		protected function updateProperties():void 
		{
			scrollRect = new Rectangle (0, 0, __width, __height);
			_content.x = -horizontalScrollPosition;
			_content.y = -verticalScrollPosition;
		};
		
		
		override protected function create():void 
		{
			super.create();
			_content = new UIContainer();
			addChild(_content);
			_dataProvider = new Array();
		};
		
		
		
		//private function test():void
		//{
			//stage.invalidate();
			////trace(stage.hasEventListener(Event.RENDER));
		//};
		protected function build():void
		{
			////trace('build' + this);
			clear();
			
			var item:ListItemRenderer;
			for each(var i:Object  in _dataProvider) 
			{
				////trace(i);
				item = new _itemRenderer();
				item.addEventListener(MouseEvent.CLICK, onItemClick);
				item.data = i;
				_items.push(item);
				_content.addChild(item);
			};
			////trace(_items.length);
			
			if (!item) return;
			_itemWidth = item.width;
			_itemHeight = item.height;
			invalidate();
			
			dispatchEvent( new ComponentEvent ( ComponentEvent.CREATION_COMPLETE));
		};
		//
		//public function clear():void 
		//{
			//
		//};
		
		override public function invalidate():void 
		{
			////trace('invalidate');
			//setTimeout(super.invalidate, Math.random()*100 + 50);
			super.invalidate();
			_itemsChanged = true;
			_propertiesChanged = true;
			//if(stage) stage.invalidate();
			//invalidateItems();
			//invalidateProperties()
		};
		
		protected function invalidateItems():void 
		{
			super.invalidate();
			_itemsChanged = true;
		}
		
		protected function invalidateProperties():void 
		{
			super.invalidate();
			_propertiesChanged = true;
		}
		
		protected function onItemClick(event:MouseEvent):void 
		{
			selectedItem = event.currentTarget.data;
			dispatchEvent(new Event(Event.CHANGE));
		};
		
		public function clear():void
		{
			for each(var i:ListItemRenderer  in _items) 
			{
				i.destroy();
			};
			_items = new Array();
			verticalScrollPosition = horizontalScrollPosition = 0;
		};
		
		public function updateDataProvider(arr:Array):void 
		{
			var c:int = 0;
			_dataProvider = arr;
			//trace('updateDataProvider : ' + arr.length);
			for each(var i:ListItemRenderer  in _items) 
			{
				//trace(_dataProvider[c]);
				i.data = _dataProvider[c];
				c++;
			};
		}
		
		public function get dataProvider():Array { return _dataProvider; };
		
		public function set dataProvider(value:Array):void 
		{
			////trace('dataProvider');
			_dataProvider = value;
			build();
		};
		
		// TO DO: добавить добавление/удаление произвольных item`ов 
		//public function add():void 
		//{
			//
		//}
		//
		override protected function updateDisplayList():void 
		{
			////trace('updateDisplayList');
			super.updateDisplayList();
			scrollRect = new Rectangle(0, 0, width, height);
			if (_itemsChanged) { updateItems(); };
			if (_propertiesChanged) updateProperties();
			dispatchEvent( new ComponentEvent ( ComponentEvent.UPDATE_COMPLETE));
			
		};
		
		protected function updateItems():void
		{
			/* 
			 * приоритет по колонкам ( если есть строки и колонки )
			 * 
			 * */
			
			////trace('updateItems', _dataProvider);
			if (!_dataProvider || !_dataProvider.length) return;
			 
			var n_c:int = _numColumns;
			var n_r:int = _numRows;
			if (_numColumns > 0 && _numRows > 0) 
			{
				n_r = Math.ceil(_dataProvider.length / n_c);
			}
			else 
			{
				if (_numColumns > 0) 
				{
					n_r = Math.ceil(_dataProvider.length / n_c);
				}
				else
				{
					n_c = Math.ceil(_dataProvider.length / n_r);
				}
			};
			////trace(n_r, n_c);
			allocateItems(n_r, n_c);
			////trace(scrollRect);
			var d_h:Number = _content.height - scrollRect.height
			var d_w:Number = _content.width - scrollRect.width
			////trace(_content.height);
			_maxVerticalScrollPosition = d_h < 0 ? 0 :d_h;
			_maxHorizontalScrollPosition =   d_w < 0 ? 0 :d_w;
			
			verticalScrollPosition = _verticalScrollPosition;
			horizontalScrollPosition = _horizontalScrollPosition;
			
			dispatchEvent( new ComponentEvent (ComponentEvent.UPDATE_COMPLETE) );
		};
		
		protected function allocateItems(numRows:int, numColumns:int):void
		{
			////trace('allocateItems : ' + numRows, numColumns);
			if (!numRows || !numColumns) return;
			/*
			 * стратегия расстановки - слева направо
			 * сверху вниз
			 * */
			var r:int = 0;
			var r_max:int = numRows  - 1;
			var c:int = 0;
			var c_max:int = numColumns - 1;
			for each(var i:ListItemRenderer  in _items) 
			{
				i.x = Math.round(c * (_itemWidth + _horizontalGap));
				i.y = Math.round(r * (_itemHeight + _verticalGap));	
				//i.alpha = 0.3
				////trace(i.x, i.y );
				if (c == c_max) 
				{
					c = 0;
					r++;
					if (r == (r_max + 1)) return;
				}
				else { c++; };
			};
		};
		
		override public function destroy():void 
		{
			clear();
			super.destroy();
		};
		
		public function get numRows():int { return _numRows; };
		
		public function set numRows(value:int):void 
		{
			if (_numRows == value) return;
			_numRows = value;
			_itemsChanged = true;
			invalidate();
		};
		
		public function get numColumns():int { return _numColumns; };
		
		public function set numColumns(value:int):void 
		{
			if (_numColumns == value) return;
			_numColumns = value;
			_itemsChanged = true;
			invalidate();
		};
		
		public function get verticalGap():Number { return _verticalGap; };
		
		public function set verticalGap(value:Number):void 
		{
			_verticalGap = value;
			_itemsChanged = true;
			invalidate();
		};
		
		public function get horizontalGap():Number { return _horizontalGap; };
		
		public function set horizontalGap(value:Number):void 
		{
			_horizontalGap = value;
			_itemsChanged = true;
			invalidate();
		};
		
		public function get itemWidth():Number { return _itemWidth; };
		
		public function get itemHeight():Number { return _itemHeight; };
		
		public function get itemRenderer():Class { return _itemRenderer; };
		
		public function set itemRenderer(value:Class):void 
		{
			_itemRenderer = value;
			build();
		};
		
		public function get selectedItem():Object { return _selectedItem; };
		
		public function set selectedItem(value:Object):void 
		{
			if (_selectedRenderer) _selectedRenderer.selected = false;
			_selectedItem = value;
			
			for each(var i:ListItemRenderer  in _items) 
			{
				if (value == i.data) 
				{
					_selectedRenderer = i;
					_selectedRenderer.selected = true;
					return;
				};
			};
		};
		
		public function get content():Sprite { return _content; };
		
		/**
		 * Установка скролла в долях от 0 до 1
		 */
		public function get verticalScrollProgress():Number { return _verticalScrollProgress; };
		
		public function set verticalScrollProgress(value:Number):void 
		{
			value = value > 1 ? 1 : value;
			value = value < 0 ? 0 : value;
			_verticalScrollProgress = value;
			verticalScrollPosition = _maxVerticalScrollPosition * value;
		};
		
		public function get horizontalScrollProgress():Number { return _horizontalScrollProgress; };
		
		public function set horizontalScrollProgress(value:Number):void 
		{
			value = value > 1 ? 1 : 0;
			value = value < 0 ? 0 : 0;
			_horizontalScrollProgress = value;
			horizontalScrollPosition = _maxHorizontalScrollPosition * value;
		};
		
		/**
		 * Максимальная позиция для скроллирования
		 */
		public function get maxHorizontalScrollPosition():Number { return _maxHorizontalScrollPosition; };
		
		public function get maxVerticalScrollPosition():Number { return _maxVerticalScrollPosition; };
		
		/**
		 * Текущая позиция скролла
		 */
		public function get horizontalScrollPosition():Number { return _horizontalScrollPosition; };
		
		public function set horizontalScrollPosition(value:Number):void 
		{
			value = value < 0 ? 0 : value;
			value = value > maxHorizontalScrollPosition ? maxHorizontalScrollPosition : value;
			_horizontalScrollPosition = value;
			
			invalidateProperties()
		};
		
		public function get verticalScrollPosition():Number { return _verticalScrollPosition; };
		
		public function set verticalScrollPosition(value:Number):void 
		{
			value = value < 0 ? 0 : value;
			value = value > maxVerticalScrollPosition ? maxVerticalScrollPosition : value;
			_verticalScrollPosition = value;
			invalidateProperties();
		};
		
		public function get items():/*ListItemRenderer*/Array { return _items; };
		
		//
		//override protected function onStageRender(event:Event = null):void 
		//{
			////trace('onStageRender');
			//super.onStageRender(event);
			//_propertiesChanged = false;
		//};
	}

}